//#define NOMINMAX

#include "Editor.h"

#include <limits>

#include "../GLRenderer.h"
#include "../BSP.h"
#include "../Camera.h"
#include "../MyWindow.h"
#include "globals.h"


#include "../leak.h"


BuilderBrush::BuilderBrush() {

	bbox_min_[0] = 0.0f;
	bbox_min_[1] = 0.0f;
	bbox_min_[2] = 0.0f;

	bbox_max_[0] = 16.0f;
	bbox_max_[1] = 16.0f;
	bbox_max_[2] = 16.0f;

	center_[0] = (bbox_max_[0] + bbox_min_[0]) * 0.5f;
	center_[1] = (bbox_max_[1] + bbox_min_[1]) * 0.5f;
	center_[2] = (bbox_max_[2] + bbox_min_[2]) * 0.5f;

	move_point_ = -1;

	selected_ = false;

	UpdateLines();

	color_[0] = 0.0f;	color_[1] = 1.0f;	color_[2] = 1.0f;
}

void BuilderBrush::Move(float move_vec[3]) {

	bbox_min_[0] += move_vec[0];
	bbox_min_[1] += move_vec[1];
	bbox_min_[2] += move_vec[2];

	bbox_max_[0] += move_vec[0];
	bbox_max_[1] += move_vec[1];
	bbox_max_[2] += move_vec[2];

	center_[0] += move_vec[0];
	center_[1] += move_vec[1];
	center_[2] += move_vec[2];

	UpdateLines();
}

bool BuilderBrush::Check(float x, float y, Camera& cam, MyBaseElement& element) {

	/*float lines[] = {	bbox_min_[0], bbox_min_[1], bbox_min_[2],
						bbox_min_[0], bbox_max_[1], bbox_min_[2],
						bbox_max_[0], bbox_min_[1], bbox_min_[2],
						bbox_max_[0], bbox_max_[1], bbox_min_[2],
						bbox_min_[0], bbox_min_[1], bbox_max_[2],
						bbox_min_[0], bbox_max_[1], bbox_max_[2],
						bbox_max_[0], bbox_min_[1], bbox_max_[2],
						bbox_max_[0], bbox_max_[1], bbox_max_[2],
						bbox_min_[0], bbox_min_[1], bbox_min_[2],
						bbox_max_[0], bbox_min_[1], bbox_min_[2],
						bbox_min_[0], bbox_min_[1], bbox_max_[2],
						bbox_max_[0], bbox_min_[1], bbox_max_[2],
						bbox_min_[0], bbox_min_[1], bbox_min_[2],
						bbox_min_[0], bbox_min_[1], bbox_max_[2],
						bbox_max_[0], bbox_min_[1], bbox_min_[2],
						bbox_max_[0], bbox_min_[1], bbox_max_[2],
						bbox_min_[0], bbox_max_[1], bbox_min_[2],
						bbox_max_[0], bbox_max_[1], bbox_min_[2],
						bbox_min_[0], bbox_max_[1], bbox_max_[2],
						bbox_max_[0], bbox_max_[1], bbox_max_[2],
						bbox_min_[0], bbox_max_[1], bbox_min_[2],
						bbox_min_[0], bbox_max_[1], bbox_max_[2],
						bbox_max_[0], bbox_max_[1], bbox_min_[2],
						bbox_max_[0], bbox_max_[1], bbox_max_[2]	};*/

	move_point_ = -1;

	float view_proj_mat[16];
	matrixMultiplyMM(view_proj_mat, const_cast<float*>(cam.projection_matrix()), const_cast<float*>(cam.view_matrix()));

	float min_dist = numeric_limits<float>::max();

	float p[3] = { x, y, 0.0f };

	for(int i = 0; i < 72; i += 3 * 2)
	{
		float v1[3], v2[3];
		MatVecMult(&lines_[i], view_proj_mat, v1);
		v1[2] = 0.0f;

		MatVecMult(&lines_[i + 3], view_proj_mat, v2);
		v2[2] = 0.0f;

		float dist = DistPointToSegment(v1, v2, p, nullptr);
		if(dist < min_dist)
		{
			min_dist = dist;
		}
	}

	if(selected_)
	{
		for(int i = 0; i < 8; i += 1)
		{
			float p1[3];

			MatVecMult(&bold_points_[ i * 3 ], view_proj_mat, p1);
			p1[2] = 0.0f;

			float dist = DistPointToPoint(p, p1, nullptr);
			float m_dist = 0.5f * (dist / element.dims()[2]) * element.dims_px()[2];
			if(m_dist < 12.0f)
			{
				//min_dist = dist;
				move_point_ = i;
				return true;
			}
		}

		for(int i = 0; i < 12; i++)
		{
			float p1[3];

			MatVecMult(&points_[ i * 3 ], view_proj_mat, p1);
			p1[2] = 0.0f;

			float dist = DistPointToPoint(p, p1, nullptr);
			float m_dist = 0.5f * (dist / element.dims()[2]) * element.dims_px()[2];
			if(m_dist < 8.0f)
			{
				cout << "weeeeeee" << endl;
				move_point_ = i + 9;
				return true;
			}
		}

		float prj_bbox_min[3], prj_bbox_max[3];
		MatVecMult(bbox_min_, view_proj_mat, prj_bbox_min);
		MatVecMult(bbox_max_, view_proj_mat, prj_bbox_max);

		float new_bbox_min[3], new_bbox_max[3];
		new_bbox_min[0] = min(prj_bbox_min[0], prj_bbox_max[0]);
		new_bbox_max[0] = max(prj_bbox_min[0], prj_bbox_max[0]);

		new_bbox_min[1] = min(prj_bbox_min[1], prj_bbox_max[1]);
		new_bbox_max[1] = max(prj_bbox_min[1], prj_bbox_max[1]);

		cout << x << endl;
		if((p[0] > new_bbox_min[0] && p[0] < new_bbox_max[0]) &&
			(p[1] > new_bbox_min[1] && p[1] < new_bbox_max[1]))
		{
			move_point_ = 8;
			return true;
		}

	}

	float m_d = 0.5f * (min_dist / element.dims()[2]) * element.dims_px()[2];
	if(m_d < 3.0f)
	{
		selected_ = true;
		return true;
	}

	selected_ = false;
	return false;

}

bool BuilderBrush::MovePoints(float dx, float dy, Camera& cam, MyBaseElement& element) {

	if(!selected_ || move_point_ == -1 || !cam.is_orthographic())
	{
		return false;
	}

	static float acc_vec[3];

	const float* proj_mat = cam.projection_matrix();
	float view_proj_mat[16];
	matrixMultiplyMM(view_proj_mat, const_cast<float*>(proj_mat), const_cast<float*>(cam.view_matrix()));

	float r_dx = 4.0f * (dx / element.dims()[2]) * (1.0f / proj_mat[0]);
	float r_dy = -4.0f * (dy / element.dims()[3]) * (1.0f / proj_mat[5]);

	float cam_x[3] = { view_proj_mat[0], view_proj_mat[4], view_proj_mat[8] };
	//normalize(cam_x[0], cam_x[1], cam_x[2]);
	Normalize(cam_x);
	float cam_y[3] = { view_proj_mat[1], view_proj_mat[5], view_proj_mat[9] };
	//normalize(cam_y[0], cam_y[1], cam_y[2]);
	Normalize(cam_y);

	float add_vec[3] = {	cam_x[0] * r_dx + cam_y[0] * r_dy, 
							cam_x[1] * r_dx + cam_y[1] * r_dy, 
							cam_x[2] * r_dx + cam_y[2] * r_dy	};

	acc_vec[0] += add_vec[0];	acc_vec[1] += add_vec[1];	acc_vec[2] += add_vec[2];
	add_vec[0] += acc_vec[0];	add_vec[1] += acc_vec[1];	add_vec[2] += acc_vec[2];

	add_vec[0] = Round(add_vec[0] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
	add_vec[1] = Round(add_vec[1] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
	add_vec[2] = Round(add_vec[2]  / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;

	acc_vec[0] -= add_vec[0];	acc_vec[1] -= add_vec[1];	acc_vec[2] -= add_vec[2];


	switch(move_point_)
	{
	case 0:
		bbox_min_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		break;
	case 1:
		bbox_max_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		break;
	case 2:
		bbox_min_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 3:
		bbox_max_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 4:
		bbox_min_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		break;
	case 5:
		bbox_max_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		break;
	case 6:
		bbox_min_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 7:
		bbox_max_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 8:
		bbox_min_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		bbox_max_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 9:
		bbox_min_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		break;
	case 10:
		bbox_max_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	
		break;
	case 11:
		bbox_min_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 12:
		bbox_min_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	
		break;
	case 13:
		bbox_min_[0] += add_vec[0];	bbox_min_[2] += add_vec[2];	
		break;
	case 14:
		bbox_max_[0] += add_vec[0];	bbox_min_[2] += add_vec[2];	
		break;
	case 15:
		bbox_min_[0] += add_vec[0];	bbox_max_[2] += add_vec[2];	
		break;
	case 16:
		bbox_max_[0] += add_vec[0];	bbox_max_[2] += add_vec[2];	
		break;
	case 17:
		bbox_max_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		break;
	case 18:
		bbox_max_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	
		break;
	case 19:
		bbox_max_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 20:
		bbox_min_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	
		break;
	}

	if(g_render_state.point_snap)
	{
		bbox_min_[0] = Round(bbox_min_[0] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
		bbox_min_[1] = Round(bbox_min_[1] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
		bbox_min_[2] = Round(bbox_min_[2] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;

		bbox_max_[0] = Round(bbox_max_[0] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
		bbox_max_[1] = Round(bbox_max_[1] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
		bbox_max_[2] = Round(bbox_max_[2] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
	}

	center_[0] = (bbox_max_[0] + bbox_min_[0]) / 2.0f;
	center_[1] = (bbox_max_[1] + bbox_min_[1]) / 2.0f;
	center_[2] = (bbox_max_[2] + bbox_min_[2]) / 2.0f;

	UpdateLines();
	cout << move_point_ << " " << proj_mat[5] << " " << proj_mat[9] << endl;

	return true;
}

void BuilderBrush::Draw() {

	glUniform3f(Renderer::render_state->current_program->uniform(COL_UNIFORM), color_[0], color_[1], color_[2]);

	glEnableVertexAttribArray(Renderer::render_state->current_program->attribute(POSITION_ATTRIBUTE));
	glVertexAttribPointer(Renderer::render_state->current_program->attribute(POSITION_ATTRIBUTE), 3, GL_FLOAT, GL_FALSE, 0, lines_);
	glDrawArrays(GL_LINES, 0, 24);
	
	if(selected_)
	{
		glPointSize(12.0f);

		glEnableVertexAttribArray(Renderer::render_state->current_program->attribute(POSITION_ATTRIBUTE));
		glVertexAttribPointer(Renderer::render_state->current_program->attribute(POSITION_ATTRIBUTE), 3, GL_FLOAT, GL_FALSE, 0, bold_points_);
		glDrawArrays(GL_POINTS, 0, 8);

		glPointSize(6.0f);

		glEnableVertexAttribArray(Renderer::render_state->current_program->attribute(POSITION_ATTRIBUTE));
		glVertexAttribPointer(Renderer::render_state->current_program->attribute(POSITION_ATTRIBUTE), 3, GL_FLOAT, GL_FALSE, 0, points_);
		glDrawArrays(GL_POINTS, 0, 12);

	}

}

void BuilderBrush::UpdateLines() {

	lines_[0] =	bbox_min_[0];	lines_[1] = bbox_min_[1];	lines_[2] = bbox_min_[2];
	lines_[3] = bbox_min_[0];	lines_[4] = bbox_max_[1];	lines_[5] = bbox_min_[2];
	lines_[6] = bbox_max_[0];	lines_[7] = bbox_min_[1];	lines_[8] = bbox_min_[2];
	lines_[9] = bbox_max_[0];	lines_[10] = bbox_max_[1];	lines_[11] = bbox_min_[2];
	lines_[12] = bbox_min_[0];	lines_[13] = bbox_min_[1];	lines_[14] = bbox_max_[2];
	lines_[15] = bbox_min_[0];	lines_[16] = bbox_max_[1];	lines_[17] = bbox_max_[2];
	lines_[18] = bbox_max_[0];	lines_[19] = bbox_min_[1];	lines_[20] = bbox_max_[2];
	lines_[21] = bbox_max_[0];	lines_[22] = bbox_max_[1];	lines_[23] = bbox_max_[2];
	lines_[24] = bbox_min_[0];	lines_[25] = bbox_min_[1];	lines_[26] = bbox_min_[2];
	lines_[27] = bbox_max_[0];	lines_[28] = bbox_min_[1];	lines_[29] = bbox_min_[2];
	lines_[30] = bbox_min_[0];	lines_[31] = bbox_min_[1];	lines_[32] = bbox_max_[2];
	lines_[33] = bbox_max_[0];	lines_[34] = bbox_min_[1];	lines_[35] = bbox_max_[2];
	lines_[36] = bbox_min_[0];	lines_[37] = bbox_min_[1];	lines_[38] = bbox_min_[2];
	lines_[39] = bbox_min_[0];	lines_[40] = bbox_min_[1];	lines_[41] = bbox_max_[2];
	lines_[42] = bbox_max_[0];	lines_[43] = bbox_min_[1];	lines_[44] = bbox_min_[2];
	lines_[45] = bbox_max_[0];	lines_[46] = bbox_min_[1];	lines_[47] = bbox_max_[2];
	lines_[48] = bbox_min_[0];	lines_[49] = bbox_max_[1];	lines_[50] = bbox_min_[2];
	lines_[51] = bbox_max_[0];	lines_[52] = bbox_max_[1];	lines_[53] = bbox_min_[2];
	lines_[54] = bbox_min_[0];	lines_[55] = bbox_max_[1];	lines_[56] = bbox_max_[2];
	lines_[57] = bbox_max_[0];	lines_[58] = bbox_max_[1];	lines_[59] = bbox_max_[2];
	lines_[60] = bbox_min_[0];	lines_[61] = bbox_max_[1];	lines_[62] = bbox_min_[2];
	lines_[63] = bbox_min_[0];	lines_[64] = bbox_max_[1];	lines_[65] = bbox_max_[2];
	lines_[66] = bbox_max_[0];	lines_[67] = bbox_max_[1];	lines_[68] = bbox_min_[2];
	lines_[69] = bbox_max_[0];	lines_[70] = bbox_max_[1];	lines_[71] = bbox_max_[2];


	bold_points_[0] = bbox_min_[0];		bold_points_[1] = bbox_min_[1];		bold_points_[2] = bbox_min_[2];
	bold_points_[3] = bbox_max_[0];		bold_points_[4] = bbox_min_[1];		bold_points_[5] = bbox_min_[2];
	bold_points_[6] = bbox_min_[0];		bold_points_[7] = bbox_min_[1];		bold_points_[8] = bbox_max_[2];
	bold_points_[9] = bbox_max_[0];		bold_points_[10] = bbox_min_[1];	bold_points_[11] = bbox_max_[2];

	bold_points_[12] = bbox_min_[0];	bold_points_[13] = bbox_max_[1];	bold_points_[14] = bbox_min_[2];
	bold_points_[15] = bbox_max_[0];	bold_points_[16] = bbox_max_[1];	bold_points_[17] = bbox_min_[2];
	bold_points_[18] = bbox_min_[0];	bold_points_[19] = bbox_max_[1];	bold_points_[20] = bbox_max_[2];
	bold_points_[21] = bbox_max_[0];	bold_points_[22] = bbox_max_[1];	bold_points_[23] = bbox_max_[2];

	
	points_[0] = center_[0];	points_[1] = bbox_min_[1];	points_[2] = bbox_min_[2];
	points_[3] = bbox_max_[0];	points_[4] = bbox_min_[1];	points_[5] = center_[2];
	points_[6] = center_[0];	points_[7] = bbox_min_[1];	points_[8] = bbox_max_[2];
	points_[9] = bbox_min_[0];	points_[10] = bbox_min_[1];	points_[11] = center_[2];

	points_[12] = bbox_min_[0];	points_[13] = center_[1];	points_[14] = bbox_min_[2];
	points_[15] = bbox_max_[0];	points_[16] = center_[1];	points_[17] = bbox_min_[2];
	points_[18] = bbox_min_[0];	points_[19] = center_[1];	points_[20] = bbox_max_[2];
	points_[21] = bbox_max_[0];	points_[22] = center_[1];	points_[23] = bbox_max_[2];

	points_[24] = center_[0];	points_[25] = bbox_max_[1];	points_[26] = bbox_min_[2];
	points_[27] = bbox_max_[0];	points_[28] = bbox_max_[1];	points_[29] = center_[2];
	points_[30] = center_[0];	points_[31] = bbox_max_[1];	points_[32] = bbox_max_[2];
	points_[33] = bbox_min_[0];	points_[34] = bbox_max_[1];	points_[35] = center_[2];
}


SelectionFrame::SelectionFrame() {

	selected_ = true;

	mode_ = SELECT_MODE;

	color_[0] = 1.0f;	color_[1] = 0.0f;	color_[2] = 0.0f;
	Update();
}

SelectionFrame::~SelectionFrame() {

}

void SelectionFrame::Add(Brush* brush) {

	selection_.insert(brush);
	//Update(brush);
	Update();

}

void SelectionFrame::Add(MovableObject* object){
	selected_objects_.insert(object);
	Update();
}

void SelectionFrame::Add(BaseEntity* entity){
	selected_entities_.insert(entity);
	Update();
}

void SelectionFrame::Add(Poly* poly){
	selected_faces_.insert(poly);
	Update();
}

void SelectionFrame::Remove(Brush* brush) {

	selection_.erase(brush);
	Update();

}

void SelectionFrame::Clear() {

	switch(mode_)
	{
	case SELECT_MODE:
		if(!selection_.empty())
		{
			for(auto brush_it = selection_.begin(); brush_it != selection_.end(); brush_it++)
			{
				(*brush_it)->set_selected(false);
			}	
			selection_.clear();
		}
		selected_ = false;

		selected_objects_.clear();
		selected_entities_.clear();

		bbox_min_[0] = std::numeric_limits<float>::max();
		bbox_min_[1] = std::numeric_limits<float>::max();
		bbox_min_[2] = std::numeric_limits<float>::max();

		bbox_max_[0] = -std::numeric_limits<float>::max();
		bbox_max_[1] = -std::numeric_limits<float>::max();
		bbox_max_[2] = -std::numeric_limits<float>::max();

		break;
	case TEX_MODE:
		if(!selected_faces_.empty())
		for(auto p_poly_it = selected_faces_.begin(); p_poly_it != selected_faces_.end(); p_poly_it++)
		{
			(*p_poly_it)->legal = true;
		}

		selected_faces_.clear();
		break;
	}

}

void SelectionFrame::Update() {

	if(selection_.empty() && selected_objects_.empty() && selected_entities_.empty())
	{
		return;
	}

	bbox_min_[0] = std::numeric_limits<float>::max();
	bbox_min_[1] = std::numeric_limits<float>::max();
	bbox_min_[2] = std::numeric_limits<float>::max();

	bbox_max_[0] = -std::numeric_limits<float>::max();
	bbox_max_[1] = -std::numeric_limits<float>::max();
	bbox_max_[2] = -std::numeric_limits<float>::max();

	for(auto sel = selection_.begin(); sel != selection_.end(); sel++)
	{
		bbox_min_[0] = min((*sel)->bbox_min()[0] , bbox_min_[0]);
		bbox_min_[1] = min((*sel)->bbox_min()[1] , bbox_min_[1]);
		bbox_min_[2] = min((*sel)->bbox_min()[2] , bbox_min_[2]);

		bbox_max_[0] = max((*sel)->bbox_max()[0] , bbox_max_[0]);
		bbox_max_[1] = max((*sel)->bbox_max()[1] , bbox_max_[1]);
		bbox_max_[2] = max((*sel)->bbox_max()[2] , bbox_max_[2]);
	}

	if(!selected_objects_.empty())
	for(auto p_sel : selected_objects_)
	{
		bbox_min_[0] = min(p_sel->bbox_min()[0] , bbox_min_[0]);
		bbox_min_[1] = min(p_sel->bbox_min()[1] , bbox_min_[1]);
		bbox_min_[2] = min(p_sel->bbox_min()[2] , bbox_min_[2]);

		bbox_max_[0] = max(p_sel->bbox_max()[0] , bbox_max_[0]);
		bbox_max_[1] = max(p_sel->bbox_max()[1] , bbox_max_[1]);
		bbox_max_[2] = max(p_sel->bbox_max()[2] , bbox_max_[2]);
	}

	for(auto p_sel : selected_entities_)
	{
		bbox_min_[0] = min(p_sel->bbox_min()[0] , bbox_min_[0]);
		bbox_min_[1] = min(p_sel->bbox_min()[1] , bbox_min_[1]);
		bbox_min_[2] = min(p_sel->bbox_min()[2] , bbox_min_[2]);

		bbox_max_[0] = max(p_sel->bbox_max()[0] , bbox_max_[0]);
		bbox_max_[1] = max(p_sel->bbox_max()[1] , bbox_max_[1]);
		bbox_max_[2] = max(p_sel->bbox_max()[2] , bbox_max_[2]);
	}

	center_[0] = (bbox_max_[0] + bbox_min_[0]) * 0.5f;
	center_[1] = (bbox_max_[1] + bbox_min_[1]) * 0.5f;
	center_[2] = (bbox_max_[2] + bbox_min_[2]) * 0.5f;

	UpdateLines();

}

void SelectionFrame::Update(Brush* new_brush) {

	bbox_min_[0] = min(new_brush->bbox_min()[0] , bbox_min_[0]);
	bbox_min_[1] = min(new_brush->bbox_min()[1] , bbox_min_[1]);
	bbox_min_[2] = min(new_brush->bbox_min()[2] , bbox_min_[2]);

	bbox_max_[0] = max(new_brush->bbox_max()[0] , bbox_max_[0]);
	bbox_max_[1] = max(new_brush->bbox_max()[1] , bbox_max_[1]);
	bbox_max_[2] = max(new_brush->bbox_max()[2] , bbox_max_[2]);

	center_[0] = (bbox_max_[0] + bbox_min_[0]) * 0.5f;
	center_[1] = (bbox_max_[1] + bbox_min_[1]) * 0.5f;
	center_[2] = (bbox_max_[2] + bbox_min_[2]) * 0.5f;

	UpdateLines();
}

bool SelectionFrame::Empty() {

	return selection_.empty() && selected_objects_.empty() && selected_entities_.empty();

}

void SelectionFrame::Draw() {

	if(selection_.empty() && selected_objects_.empty() && selected_entities_.empty())
	{
		return;
	}

	if(mode_ != EDIT_MODE)
	{
		glLineWidth(4.0f);
		BuilderBrush::Draw();
		glLineWidth(1.0f);
	} else
	{
		for(auto brush = selection_.begin(); brush != selection_.end(); brush++)
		{
			(*brush)->DrawVertices();
		}
	}

}

bool SelectionFrame::CheckBrush(float x, float y, Camera& cam, MyBaseElement& element) {

	if(g_brushes.empty() || mode_ != SELECT_MODE)
	{
		return false;
	}

	float view_proj_mat[16];
	matrixMultiplyMM(view_proj_mat, const_cast<float*>(cam.projection_matrix()), const_cast<float*>(cam.view_matrix()));

	float min_dist = numeric_limits<float>::max();
	//int min_index = -1;
	auto min_it_brush = g_brushes.end();
	auto min_it_obj = g_static_meshes.end();
	auto min_it_ent = g_entities.end();

	float p[3] = { x, y, 0.0f };

	if(cam.is_orthographic())
	{
		for(auto brush = g_brushes.begin(); brush != g_brushes.end(); brush++)
		{
			for(auto polygon = (*brush).polygons().begin(); polygon != (*brush).polygons().end(); polygon++)
			{
				for(auto point1 = (*polygon).points.begin(); point1 != (*polygon).points.end(); point1 += 3)
				{
					vector<float>::iterator point2;
					if(point1 == (*polygon).points.end() - 3)
					{
						point2 = (*polygon).points.begin();
					} else
					{
						point2 = point1 + 3;
					}

					float v1[3], v2[3], res_vec[3], z1, z2;
					MatVecMult(&point1[0], view_proj_mat, v1);
					z1 = v1[2];
					v1[2] = 0.0f;

					MatVecMult(&point2[0], view_proj_mat, v2);
					z2 = v2[2];
					v2[2] = 0.0f;

					float dist = DistPointToSegment(v1, v2, p, res_vec);
					float m_d = 0.5f * (dist / element.dims()[2]) * element.dims_px()[2];
					//if(dist < min_dist && m_d < 3.0f)
					if(m_d < 3.0f)
					{
						float p_on_line[3] = {p[0] + res_vec[0], p[1] + res_vec[1], 0.0f};
						float t;
						if(abs(p_on_line[0] - v2[0]) > abs(p_on_line[1] - v2[1]))
						{
							t = (p_on_line[0] - v2[0])/(v1[0] - v2[0]);
						} else
						{
							t = (p_on_line[1] - v2[1])/(v1[1] - v2[1]);
						}
						p_on_line[2] = abs(t * z1 + (1.0f - t)*z2);

						if(p_on_line[2] < min_dist)
						{
							//min_dist = dist;
							min_dist = p_on_line[2];
							min_it_brush = brush;
						}
					}
				}
			}
		}

		glm::mat4x4 mmm = glm::make_mat4x4(view_proj_mat);

		for(auto mesh = g_static_meshes.begin(); mesh != g_static_meshes.end(); mesh++)
		{
			float dist;
			if((*mesh).Check(x, y, mmm, element.dims(), element.dims_px(), &dist))
			{
				if(dist < min_dist)
				{
					min_dist = dist;
					min_it_brush = g_brushes.end();
					min_it_obj = mesh;
				}
			}
		}

		for(auto entity = g_entities.begin(); entity != g_entities.end(); entity++)
		{
			float dist;
			if((*entity)->Check(x, y, mmm, element.dims(), element.dims_px(), &dist))
			{
				cout << "ddd" << endl;
				if(dist < min_dist)
				{
					min_dist = dist;
					min_it_brush = g_brushes.end();
					min_it_obj = g_static_meshes.end();
					min_it_ent = entity;
				}
			}
		}
	} else
	{
		const float* origin = cam.world_position();
		float unproj_point[3];
		float inv_mat[16];
		//InvMat(view_proj_mat, inv_mat);
		gluInvertMatrix(view_proj_mat, inv_mat);
		p[2] = 1.0f;
		MatVecMult(p, inv_mat, unproj_point);
		float ray[3] = {	unproj_point[0] - origin[0],
							unproj_point[1] - origin[1],
							unproj_point[2] - origin[2]	};
		//normalize(ray[0], ray[1], ray[2]);
		Normalize(ray);
		//float  x;
		for(auto brush = g_brushes.begin(); brush != g_brushes.end(); brush++)
		{
			float dist;
			if((*brush).TraceL(origin, ray, &dist))
			{
				if(dist < min_dist)
				{
					min_dist = dist;
					min_it_brush = brush;
				}
			}
		}

		for(auto mesh = g_static_meshes.begin(); mesh != g_static_meshes.end(); mesh++)
		{
			float dist;
			if((*mesh).TraceL(origin, ray, &dist))
			{
				if(dist < min_dist)
				{
					min_it_brush = g_brushes.end();
					min_dist = dist;
					min_it_obj = mesh;
				}
			}
		}

		for(auto entity = g_entities.begin(); entity != g_entities.end(); entity++)
		{
			float dist;
			if((*entity)->TraceL(origin, ray, &dist))
			{
				if(dist < min_dist)
				{
					min_it_brush = g_brushes.end();
					min_it_obj = g_static_meshes.end();
					min_it_ent = entity;
					min_dist = dist;
				}
			}
		}
	}

	if(min_it_brush == g_brushes.end())
	{
		//sel_changed_signal.Fire();
		//return false;
	} else
	{
		//selection_.insert(&g_brushes[ min_index ]);
		//Add(&g_brushes[ min_index ]);
		Add(&(*min_it_brush));
		(*min_it_brush).set_selected(true);
		selected_ = true;
		sel_changed_signal.Fire();
		return true;
	}

	if(min_it_obj != g_static_meshes.end())
	{
		cout << "aaa" << endl;
		Add(&(*min_it_obj));
		selected_ = true;
		sel_changed_signal.Fire();
		return true;
	} else

	if(min_it_ent != g_entities.end())
	{
		cout << "entent" << endl;
		Add((*min_it_ent).get());
		selected_ = true;
		sel_changed_signal.Fire();
		return true;
	}

	return false;

}

bool SelectionFrame::CheckMesh(float x, float y, Camera& cam, MyBaseElement& element){
	if(g_static_meshes.empty() || mode_ != SELECT_MODE)
	{
		return false;
	}

	glm::mat4x4 view_proj_mat = glm::make_mat4(cam.projection_matrix()) * glm::make_mat4(cam.view_matrix());

	float min_dist = numeric_limits<float>::max();
	auto min_it = g_static_meshes.end();

	float p[3] = { x, y, 0.0f };

	if(cam.is_orthographic())
	{
		for(auto mesh = g_static_meshes.begin(); mesh != g_static_meshes.end(); mesh++)
		{
			if((*mesh).Check(x, y, view_proj_mat, element.dims(), element.dims_px()))
			{
				min_it = mesh;
				break;
			}
		}
	} else
	{
		const float* origin = cam.world_position();
		float unproj_point[3];
		float inv_mat[16];
		//InvMat(view_proj_mat, inv_mat);
		gluInvertMatrix(&view_proj_mat[0][0], inv_mat);
		p[2] = 1.0f;
		MatVecMult(p, inv_mat, unproj_point);
		float ray[3] = {	unproj_point[0] - origin[0],
							unproj_point[1] - origin[1],
							unproj_point[2] - origin[2]	};
		//normalize(ray[0], ray[1], ray[2]);
		Normalize(ray);

		for(auto mesh = g_static_meshes.begin(); mesh != g_static_meshes.end(); mesh++)
		{
			float dist;
			if((*mesh).TraceL(origin, ray, &dist))
			{
				if(dist < min_dist)
				{
					min_dist = dist;
					min_it = mesh;
				}
			}
		}
	}

	if(min_it != g_static_meshes.end())
	{
		cout << "aaa" << endl;
		Add(&(*min_it));
		return true;
	}
	return false;
}

bool SelectionFrame::CheckEntity(float x, float y, Camera& cam, MyBaseElement& element){
	if(g_entities.empty() || mode_ != SELECT_MODE)
	{
		return false;
	}

	glm::mat4x4 view_proj_mat = glm::make_mat4(cam.projection_matrix()) * glm::make_mat4(cam.view_matrix());

	float min_dist = numeric_limits<float>::max();
	auto min_it = g_entities.end();

	float p[3] = { x, y, 0.0f };

	if(cam.is_orthographic())
	{
		for(auto entity = g_entities.begin(); entity != g_entities.end(); entity++)
		{
			//if((*entity)->Check(x, y, view_proj_mat, element))
			if((*entity)->Check(x, y, view_proj_mat, element.dims(), element.dims_px()))
			{
				min_it = entity;
				break;
			}
		}
	} else
	{

	}

	if(min_it != g_entities.end())
	{
		cout << "aaa" << endl;
		Add((*min_it).get());
		return true;
	}
	return false;
}

void SelectionFrame::DeleteSelection() {

	if(selection_.empty() && selected_objects_.empty() && selected_entities_.empty())
	{
		return;
	}

	for(auto brush = selection_.begin(); brush != selection_.end(); brush++)
	{
		if(!g_brushes.empty())
		for(auto brush2 = g_brushes.begin(); brush2 != g_brushes.end(); brush2++)
		{
			if(&(*brush2) == (*brush))
			{
				g_brushes.erase(brush2);
				break;
			}
		}
	}

	for(auto& p_obj : selected_objects_)
	{
		for(auto obj_it = g_static_meshes.begin(); obj_it != g_static_meshes.end(); obj_it++)
		{
			if(&(*obj_it) == p_obj)
			{
				g_static_meshes.erase(obj_it);
				break;
			}
		}
	}

	for(auto& p_ent : selected_entities_)
	{
		for(auto ent_it = g_entities.begin(); ent_it != g_entities.end(); ent_it++)
		{
			if((*ent_it).get() == p_ent)
			{
				g_entities.erase(ent_it);
				break;
			}
		}
	}

	//selection_.clear();
	Clear();

}

void SelectionFrame::CopySelection() {
	if(selection_.empty() || mode_ != SELECT_MODE)
	{
		return;
	}

	auto selection = selection_;
	Clear();
	for(auto p_brush_it = selection.begin(); p_brush_it != selection.end(); p_brush_it++)
	{
		g_brushes.push_back(**p_brush_it);
		auto added_it = g_brushes.end();
		added_it--;
		selection_.insert(&*added_it);
		(*added_it).set_selected(true);
	}
	selected_ = true;
	Update();
}

bool SelectionFrame::Check(float x, float y, Camera& cam, MyBaseElement& element) {
	if(selection_.empty() && selected_objects_.empty() && selected_entities_.empty())
	{
		return false;
	}

	float view_proj_mat[16];

	switch(mode_)
	{
	case EDIT_MODE:
		matrixMultiplyMM(view_proj_mat, const_cast<float*>(cam.projection_matrix()), const_cast<float*>(cam.view_matrix()));

		for(auto brush = selection_.begin(); brush != selection_.end(); brush++)
		{
			(*brush)->SelectPoints(x, y, view_proj_mat, element.dims(), element.dims_px());
		}
		return true;
	case TEX_MODE: 
		if(!cam.is_orthographic())
		{
			matrixMultiplyMM(view_proj_mat, const_cast<float*>(cam.projection_matrix()), const_cast<float*>(cam.view_matrix()));

			const float* origin = cam.world_position();
			float unproj_point[3];
			float inv_mat[16];
			gluInvertMatrix(view_proj_mat, inv_mat);
			float p[3] = { x, y, 1.0f };
			MatVecMult(p, inv_mat, unproj_point);
			float ray[3] = {	unproj_point[0] - origin[0],
								unproj_point[1] - origin[1],
								unproj_point[2] - origin[2]	};
			//normalize(ray[0], ray[1], ray[2]);
			Normalize(ray);

			float min_dist = numeric_limits<float>::max();
			Poly* p_closest = nullptr;

			for(auto brush = selection_.begin(); brush != selection_.end(); brush++)
			{
				float dist;
				Poly* p_closest2;
				if((*brush)->SelectFace(origin, ray, &dist, &p_closest2))
				{
					if(dist < min_dist)
					{
						min_dist = dist;
						p_closest = p_closest2;
						//min_it = brush;
					}
				}
			}

			if(p_closest != nullptr)
			{
				p_closest->legal = false;
				selected_faces_.insert(p_closest);
				sel_changed_signal.Fire();
				return true;
			} else
			{
				//sel_changed_signal.Fire();
				return false;
			}
		}
	}

	if(!cam.is_orthographic())
	{
		return false;
	}

	bool b = BuilderBrush::Check(x, y, cam, element);
	selected_ = true;
	return b;
}

bool SelectionFrame::MovePoints(float dx, float dy, Camera& cam, MyBaseElement& element) {

	if(!selected_ || (move_point_ == -1 && mode_ != EDIT_MODE) || !cam.is_orthographic())
	{
		return false;
	}

	static float acc_vec[3];

	const float* proj_mat = cam.projection_matrix();
	float view_proj_mat[16];
	matrixMultiplyMM(view_proj_mat, const_cast<float*>(proj_mat), const_cast<float*>(cam.view_matrix()));

	float r_dx = 4.0f * (dx / element.dims()[2]) * (1.0f / proj_mat[0]);
	float r_dy = -4.0f * (dy / element.dims()[3]) * (1.0f / proj_mat[5]);

	float cam_x[3] = { view_proj_mat[0], view_proj_mat[4], view_proj_mat[8] };
	//normalize(cam_x[0], cam_x[1], cam_x[2]);
	Normalize(cam_x);
	float cam_y[3] = { view_proj_mat[1], view_proj_mat[5], view_proj_mat[9] };
	//normalize(cam_y[0], cam_y[1], cam_y[2]);
	Normalize(cam_y);

	float add_vec[3] = {	cam_x[0] * r_dx + cam_y[0] * r_dy, 
							cam_x[1] * r_dx + cam_y[1] * r_dy, 
							cam_x[2] * r_dx + cam_y[2] * r_dy	};

	acc_vec[0] += add_vec[0];	acc_vec[1] += add_vec[1];	acc_vec[2] += add_vec[2];
	add_vec[0] += acc_vec[0];	add_vec[1] += acc_vec[1];	add_vec[2] += acc_vec[2];


	add_vec[0] = Round(add_vec[0] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
	add_vec[1] = Round(add_vec[1] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
	add_vec[2] = Round(add_vec[2] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;

	acc_vec[0] -= add_vec[0];	acc_vec[1] -= add_vec[1];	acc_vec[2] -= add_vec[2];

	
	if(mode_ == EDIT_MODE)
	{
		for(auto p_brush = selection_.begin(); p_brush != selection_.end(); p_brush++)
		{
			(*p_brush)->MoveSelected(add_vec, g_render_state.grid_size);
		}
		return true;
	}

	static float old_bbox_min[3], old_bbox_max[3];

	if(bbox_min_[0] < bbox_max_[0] && bbox_min_[1] < bbox_max_[1] && bbox_min_[2] < bbox_max_[2])
	{
		copy(bbox_min_, bbox_min_ + 3, old_bbox_min);
		copy(bbox_max_, bbox_max_ + 3, old_bbox_max);
	}

	switch(move_point_)
	{
	case 0:
		bbox_min_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];
		break;
	case 1:
		bbox_max_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		break;
	case 2:
		bbox_min_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 3:
		bbox_max_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 4:
		bbox_min_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		break;
	case 5:
		bbox_max_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		break;
	case 6:
		bbox_min_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 7:
		bbox_max_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 8:
		bbox_min_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		bbox_max_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		//for(auto brush = selection_.begin(); brush != selection_.end(); brush++)
		//{
		//	(*brush)->Move(add_vec);
		//}
		break;
	case 9:
		bbox_min_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		break;
	case 10:
		bbox_max_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	
		break;
	case 11:
		bbox_min_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 12:
		bbox_min_[0] += add_vec[0];	bbox_min_[1] += add_vec[1];	
		break;
	case 13:
		bbox_min_[0] += add_vec[0];	bbox_min_[2] += add_vec[2];	
		break;
	case 14:
		bbox_max_[0] += add_vec[0];	bbox_min_[2] += add_vec[2];	
		break;
	case 15:
		bbox_min_[0] += add_vec[0];	bbox_max_[2] += add_vec[2];	
		break;
	case 16:
		bbox_max_[0] += add_vec[0];	bbox_max_[2] += add_vec[2];	
		break;
	case 17:
		bbox_max_[1] += add_vec[1];	bbox_min_[2] += add_vec[2];	
		break;
	case 18:
		bbox_max_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	
		break;
	case 19:
		bbox_max_[1] += add_vec[1];	bbox_max_[2] += add_vec[2];	
		break;
	case 20:
		bbox_min_[0] += add_vec[0];	bbox_max_[1] += add_vec[1];	
		break;
	}

	for(auto p_obj : selected_objects_)
	{
		p_obj->Rescale(old_bbox_min, old_bbox_max, bbox_min_, bbox_max_);
	}

	for(auto p_ent : selected_entities_)
	{
		p_ent->Rescale(old_bbox_min, old_bbox_max, bbox_min_, bbox_max_);
	}

	if(g_render_state.point_snap)
	{
		bool bb = false;
		if(bbox_min_[0] != bbox_max_[0] && bbox_min_[1] != bbox_max_[1] && bbox_min_[2] != bbox_max_[2])
		{
			bb = true;
		}

		bbox_min_[0] = Round(bbox_min_[0] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
		bbox_min_[1] = Round(bbox_min_[1] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
		bbox_min_[2] = Round(bbox_min_[2] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;

		bbox_max_[0] = Round(bbox_max_[0] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
		bbox_max_[1] = Round(bbox_max_[1] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;
		bbox_max_[2] = Round(bbox_max_[2] / (float)g_render_state.grid_size) * (float)g_render_state.grid_size;

	}

	center_[0] = (bbox_max_[0] + bbox_min_[0]) / 2.0f;
	center_[1] = (bbox_max_[1] + bbox_min_[1]) / 2.0f;
	center_[2] = (bbox_max_[2] + bbox_min_[2]) / 2.0f;

	//Update();
	//UpdateLines();

	//cout << "333333" << endl;
	if(bbox_min_[0] >= bbox_max_[0] || bbox_min_[1] >= bbox_max_[1] || bbox_min_[2] >= bbox_max_[2])
	{
		goto exit;
		//return true;
	}
	//cout << "444444444" << endl;
	for(auto p_brush = selection_.begin(); p_brush != selection_.end(); p_brush++)
	{
		(*p_brush)->Rescale(old_bbox_min, old_bbox_max, bbox_min_, bbox_max_);
		(*p_brush)->UpdateUVs();
	}
	//cout << move_point_ << " " << proj_mat[5] << " " << proj_mat[9] << endl;

	exit:

	Update();
	UpdateLines();
	return true;
}

void SelectionFrame::Rotate(const float* axis, const float angle) {

	for(auto brush = selection_.begin(); brush != selection_.end(); brush++)
	{
		(*brush)->Rotate(axis, angle, center_);
		(*brush)->UpdateUVs();
	}

	for(auto p_obj : selected_objects_)
	{
		p_obj->Rotate(glm::vec3(axis[0], axis[1], axis[2]), glm::radians(angle));
	}

	Update();

}

void SelectionFrame::RotateFromView(const float angle, Camera& cam) {

	if(selection_.empty() && selected_objects_.empty() && selected_entities_.empty())
	{
		return;
	}

	switch(mode_)
	{
	case SELECT_MODE:
	case EDIT_MODE:
		float axis[3], view_proj_mat[16];
		matrixMultiplyMM(view_proj_mat, const_cast<float*>(cam.projection_matrix()), const_cast<float*>(cam.view_matrix()));

		axis[0] = view_proj_mat[2];
		axis[1] = view_proj_mat[6];
		axis[2] = view_proj_mat[10];

		Rotate(axis, angle);
		break;
	case TEX_MODE:

		break;
	}

}

void SelectionFrame::SetFreezeTexture(bool b) {

	if(!selection_.empty())
	{
		for(auto brush_it = selection_.begin(); brush_it != selection_.end(); brush_it++)
		{
			(*brush_it)->set_freeze_texture(b);
		}
	}

}

void SelectionFrame::SetTexrure(shared_ptr<GLTexture> tex) {

	switch(mode_) {
	case SELECT_MODE:
		if(!selection_.empty())
		for(auto p_brush_it = selection_.begin(); p_brush_it != selection_.end(); p_brush_it++)
		{
			(*p_brush_it)->SetTexture(tex);
		}
		break;
	case TEX_MODE:
		if(!selected_faces_.empty())
		{
			for(auto p_face_it = selected_faces_.begin(); p_face_it != selected_faces_.end(); p_face_it++)
			{
				(*p_face_it)->tex = tex;
			}
		} else
		{
			if(!selection_.empty())
			for(auto p_brush_it = selection_.begin(); p_brush_it != selection_.end(); p_brush_it++)
			{
				(*p_brush_it)->SetTexture(tex);
			}
		}
		break;
	}

}

void SelectionFrame::ShiftTexture(const float dvec[2]) {

	if(selected_faces_.empty())
	{
		return;
	}

	for(auto face = selected_faces_.begin(); face != selected_faces_.end(); face++)
	{
		(*face)->tex_vec[0][3] += dvec[0];
		(*face)->tex_vec[1][3] += dvec[1];
	}
	
	for(auto brush_it = selection_.begin(); brush_it != selection_.end(); brush_it++)
	{
		(*brush_it)->UpdateUVs();
	}

}

void SelectionFrame::RotateTexture(float angle) {

	if(selected_faces_.empty())
	{
		return;
	}

	for(auto face = selected_faces_.begin(); face != selected_faces_.end(); face++)
	{
		/*float axis[3];
		Cross(axis, &(*face)->tex_vec[0][0], &(*face)->tex_vec[1][0]);
		Normalize(axis);
		float rot_matrix[16];
		matrixSetIdentityM(rot_matrix);
		matrixSetRotateM(rot_matrix, angle, axis[0], axis[1], axis[2]);
		float new_vecs[2][3];

		MatVecMult(&(*face)->tex_vec[0][0], rot_matrix, &new_vecs[0][0]);
		MatVecMult(&(*face)->tex_vec[1][0], rot_matrix, &new_vecs[1][0]);
		
		copy(&new_vecs[0][0], &new_vecs[0][0] + 3, &(*face)->tex_vec[0][0]);
		copy(&new_vecs[1][0], &new_vecs[1][0] + 3, &(*face)->tex_vec[1][0]);*/

		(*face)->tex_angle += angle;
	}
	
	for(auto brush_it = selection_.begin(); brush_it != selection_.end(); brush_it++)
	{
		(*brush_it)->UpdateUVs();
	}

}

void SelectionFrame::ScaleTexture(float ds) {

	if(selected_faces_.empty())
	{
		for(auto brush_it = selection_.begin(); brush_it != selection_.end(); brush_it++)
		{
			(*brush_it)->ScaleTexture(ds);
		}
		return;
	}

	int axis;
	ds < 0 ? axis = 1 : axis = 0;
	for(auto face = selected_faces_.begin(); face != selected_faces_.end(); face++)
	{
		(*face)->tex_vec[axis][0] *= fabs(ds);
		(*face)->tex_vec[axis][1] *= fabs(ds);
		(*face)->tex_vec[axis][2] *= fabs(ds);
	}

	for(auto brush_it = selection_.begin(); brush_it != selection_.end(); brush_it++)
	{
		(*brush_it)->UpdateUVs();
	}

}

void SelectionFrame::ResetTexture() {

	if(selected_faces_.empty())
	{
		if(!selection_.empty())
		{
			for(auto brush_it = selection_.begin(); brush_it != selection_.end(); brush_it++)
			{
				(*brush_it)->ResetTexture();
			}
		}
		return;
	} else
	{
		for(auto face = selected_faces_.begin(); face != selected_faces_.end(); face++)
		{
			(*face)->tex_vec[0][0] = (*face)->tex_vec[0][1] = (*face)->tex_vec[0][2] = (*face)->tex_vec[0][3] = 0.0f;
			(*face)->tex_vec[1][0] = (*face)->tex_vec[1][1] = (*face)->tex_vec[1][2] = (*face)->tex_vec[1][3] = 0.0f;
			(*face)->tex_angle = 0.0f;
		}
	}
	for(auto brush_it = selection_.begin(); brush_it != selection_.end(); brush_it++)
	{
		(*brush_it)->UpdateUVs();
	}
}

int SelectionFrame::GetSmoothingGroup() {

	if(mode_ != TEX_MODE || selected_faces_.empty())
	{
		return -1;
	}

	auto first = selected_faces_.begin();
	int group = (*first)->smoothing_group;
	first++;
	for(auto face = first; face != selected_faces_.end(); face++)
	{
		if((*face)->smoothing_group != group)
		{
			return -1;
		}
	}

	return group;
}

void SelectionFrame::SetSmoothingGroup(int group){
	if(mode_ != TEX_MODE || selected_faces_.empty())
	{
		return;
	}

	for(auto face = selected_faces_.begin(); face != selected_faces_.end(); face++)
	{
		(*face)->smoothing_group = group;
	}
}

bool SelectionFrame::GetTexVecs(float vecs[2][4]){
	if(mode_ != TEX_MODE || selected_faces_.empty())
	{
		return false;
	}

	auto first = selected_faces_.begin();
	copy(&(*first)->tex_vec[0][0], &(*first)->tex_vec[0][4], &vecs[0][0]);
	copy(&(*first)->tex_vec[1][0], &(*first)->tex_vec[1][4], &vecs[1][0]);
	first++;
	for(auto face = first; face != selected_faces_.end(); face++)
	{
		auto vec = (*face)->tex_vec;
		if(vec[0][0] != vecs[0][0] || vec[0][1] != vecs[0][1] || vec[0][2] != vecs[0][2] || vec[0][3] != vecs[0][3] ||
			vec[1][0] != vecs[1][0] || vec[1][1] != vecs[1][1] || vec[1][2] != vecs[1][2] || vec[1][3] != vecs[1][3]	)
		{
			return false;
		}
	}
	return true;
}
void SelectionFrame::SetTexVecs(float vecs[2][4]) {
	if(mode_ != TEX_MODE || selected_faces_.empty())
	{
		return;
	}

	for(auto face = selected_faces_.begin(); face != selected_faces_.end(); face++)
	{
		copy(&vecs[0][0], &vecs[0][4], &(*face)->tex_vec[0][0]);
		copy(&vecs[1][0], &vecs[1][4], &(*face)->tex_vec[1][0]);
	}

	for(auto brush : selection_)
	{
		brush->UpdateUVs();
	}
}

bool SelectionFrame::GetTexAndAngle(shared_ptr<GLTexture>& tex, float& angle){
	if(mode_ != TEX_MODE || selected_faces_.empty())
	{
		return false;
	}

	auto first = selected_faces_.begin();
	tex = (*first)->tex;
	angle = (*first)->tex_angle;
	first++;
	for(auto face = first; face != selected_faces_.end(); face++)
	{
		if((*face)->tex != tex || (*face)->tex_angle != angle)
		{
			return false;
		}
	}
	return true;
}

void SelectionFrame::SetTexAngle(float angle){
	if(mode_ != TEX_MODE || selected_faces_.empty())
	{
		return;
	}
	for(auto face = selected_faces_.begin(); face != selected_faces_.end(); face++)
	{
		(*face)->tex_angle = angle;
	}
	for(auto brush : selection_)
	{
		brush->UpdateUVs();
	}
}
